#include "wrapper.h"
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
extern int errno;
int pidA [12] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};

/* 
 * Name:		uri_entered_cb
 * Input arguments:	'entry'-address bar where the url was entered
 *			'data'-auxiliary data sent along with the event
 * Output arguments:	void
 * Function:		When the user hits the enter after entering the url
 *			in the address bar, 'activate' event is generated
 *			for the Widget Entry, for which 'uri_entered_cb'
 *			callback is called. Controller-tab captures this event
 *			and sends the browsing request to the router(/parent)
 *			process.
 */
void uri_entered_cb(GtkWidget* entry, gpointer data)
{

	if(!data)
		return;
	// Create a new browser_window
	browser_window *b_window = ((browser_window*)data); 
	// Get the tab index where the URL is to be rendered
	int tab_index = query_tab_id_for_request(entry, data);
	if(tab_index <= 0 || tab_index > 10)
	{
		// Fill in your error handling code here.
		perror("You Shall Not Do This \n");
		return;

	}

	// Get the URL.
	char* uri = get_entered_uri(entry);

	// Prepare 'request' packet to send to router (/parent) process.
	child_req_to_parent req;

	// Fill in your code here.
	if(strlen(uri) < 512)
	{
	// enter req.type
		req.type = NEW_URI_ENTERED;
	// fill in 'render in tab' field
		req.req.uri_req.render_in_tab = tab_index;	
	// fill in 'uri' field
		strcpy(req.req.uri_req.uri,uri);
	// Send the request through the proper FD.
		comm_channel channel = b_window->channel;
		write(channel.child_to_parent_fd[1],&req,sizeof(child_req_to_parent));
		return;
	}
	else
	{
		perror("Too Long of String, Or Bad String \n");
		return;
	}
}

/*
 * Name:		wait_for_browsing_req
 * Input Arguments:	fds[] - file descriptor on which
 *			'ordinary' child tab listen for request
 *			from 'controller' tab to render web pages.
 * Output arguments:    0-sucess
 *			-1- otherwise
 * Function:		The 'ordinary' child-tabs processes perform
 *			two tasks at tandem.
 *			1). Process GTK+ window-related events
 *			2). Listen for URL rendering requests from
 *			    'controller' tab.
 */
int wait_for_browsing_req(int fds[2], browser_window *b_window)
{
	int test;
	int fd;
	// Close file descriptors we won't use
	//Already Closed in previous function create tab proc

	// Set up for non-blocking IO
	int flags = fcntl(fd, F_GETFL, 0);
	fcntl (fds[0], F_SETFL, flags | O_NONBLOCK);

	// Set up flags for fcntl so we can change some file descriptors

	// Continuous loop of checking requests and processing browser events
	while(1)
	{
		usleep(5000);
		// Alternatively read incoming requests from
		// 'controller-tab' and process GTK+ events //Controller or Router? I would assume Router as the controller had already sent a message to the router!!
		// for the window
	
		// Create a new requirement, read bytes from the proper FD.
		child_req_to_parent tmpReq;
		tmpReq.type = NULL_TAB;
		/* Use this code in the following case: 
		// If read received no data && errno == EAGAIN - just process any pending events and move along.
		
			// No browsing request from 'controller' tab - Router
			// Hence process GTK+ window related function (non-blocking).
			process_single_gtk_event();
		*/
		// Data! Read what it is and fill in the proper request.
		if(test = read(fds[0],&tmpReq,sizeof(child_req_to_parent)), test == -1 && errno == EAGAIN)
		{
			process_single_gtk_event();
		}

			// There is a browsing request from the 
			// controller tab. Render the requested URL
			// on current tab.
		else if(tmpReq.type == NEW_URI_ENTERED)
		{
			char* uri = tmpReq.req.uri_req.uri;
			test = render_web_page_in_tab(uri,b_window);
			if(test == 0)
			{
				break;
			}
			else
			{
					perror("Failed To Display Webpage \n");
					return -1;
			}
				
			
		}
			// Handle all request types of CREATE_TAB, NEW_URI_ENTERED, 
			// and TAB_KILLED; for example, with a switch.


			// This processes any events left in the browser 
			// and shuts down the window.  Use this to handle TAB_KILLED.
			/*
			case TAB_KILLED:
				process_all_gtk_events();
				return 0;
			*/
		else if(tmpReq.type == TAB_KILLED)
		{
			close(b_window->channel.parent_to_child_fd[0]);
			close(b_window->channel.child_to_parent_fd[1]);
			process_all_gtk_events();
			return 1; //Signifies tab killed, and child exits.
		}
		
		tmpReq.type = NULL_TAB;

	}

	return 0;
}


void kill_all(comm_channel* channel, int total_tabs, int actual_tab_cnt)
{
	int status = 0;
	child_req_to_parent tmpReq;
	
	tmpReq.type = TAB_KILLED;
	int i;
	for(i = 1; i < total_tabs;i++)
	{
		if(pidA[i] != 0)
		{
			write(channel[i].parent_to_child_fd[1],&tmpReq,sizeof(child_req_to_parent));
			waitpid(pidA[i],&status,0);
			pidA[i] = 0;
			actual_tab_cnt--;
		}
		if(actual_tab_cnt == 0)
		{
			break;
		}
	}
	
}


/*
 * Name:		wait_for_child_reqs
 * Input Arguments:	'total_tabs': Number of tabs created so far
 * Output arguments:  	0 : Success
 *			-1: Otherwise
 * Function:		Router (/parent) process listens for request from
 *			'controller' tab and performs the required 
 *			functionality based on request code.
 */
int wait_for_child_reqs(comm_channel* channel, int total_tabs, int actual_tab_cnt)
{
	int status = 0;
	int test;
	int fd;
	child_req_to_parent tmpReq;
	tmpReq.type = NULL_TAB;
	int tmp_index = 0;
	// Continue listening for child requests 
	while(1)
	{
		// Sleep for 0.5 sec so we don't waste CPU time
		usleep(500000);
		if(actual_tab_cnt == 0)
		{
			return 4;
		}
	
		while(pidA[tmp_index] == 0)//Stops code from reading a closed channel
		{
			tmp_index++;
		}

		// Set the read FD to noblock for all tabs; remember to check for error returns!
		if(tmp_index >= total_tabs)
		{
			tmp_index = 0;
		}
		

		int flags = fcntl(fd, F_GETFL, 0);
		fcntl (channel[tmp_index].child_to_parent_fd[0], F_SETFL, flags | O_NONBLOCK);
		
		if(test = read(channel[tmp_index].child_to_parent_fd[0],&tmpReq,sizeof(child_req_to_parent)), test == -1 && errno == EAGAIN)
		{
			tmp_index++;
			tmpReq.type = NULL_TAB;
			//Do nothing basically, used re-read as nothing was read.
		}
	
		
		else if(tmpReq.type == CREATE_TAB)
		{
			if(total_tabs <= 10)
			{
				printf("Got To Create Tab \n",NULL); //Don't need this
				total_tabs++;
				create_proc_for_new_tab(channel,tmpReq.req.new_tab_req.tab_index,actual_tab_cnt);
				return 1;
			}
			else
			{
				perror("Too Many Tabs Have Been Created, Perhaps You Should Use The Other Tabs");
				break;
			}
		}


			// Poll (read) all tabs that exist.
			// This will handle CREATE_TAB, NEW_URI_ENTERED, and TAB_KILLED.
			//If create tab -> 1, if New_URI -> 2, if Tab_killed -> 3
		else if(tmpReq.type == NEW_URI_ENTERED)
		{
			printf("Got To URL TAB \n",NULL); //Don't Need this
			if(pidA[tmpReq.req.uri_req.render_in_tab] == 0)
			{
				perror("TAB HAS ALREADY BEEN CLOSED");
				break;
			}
			write(channel[tmpReq.req.uri_req.render_in_tab].parent_to_child_fd[1],&tmpReq,sizeof(child_req_to_parent));
			return 2;
		}
	
		else if(tmpReq.type == TAB_KILLED)
		{
			
			printf("Got To Tab Killed \n",NULL); //Don't Need This
			if(tmpReq.req.killed_req.tab_index == 0)
			{
				
				printf("Closing Controller Tab \n",NULL);
				close(channel[tmpReq.req.killed_req.tab_index].child_to_parent_fd[1]);
				close(channel[tmpReq.req.killed_req.tab_index].parent_to_child_fd[0]);
				return 4;
			}
			else
			{
				printf("Channel ID: %d \n",tmpReq.req.killed_req.tab_index); //Don't need this
				write(channel[tmpReq.req.killed_req.tab_index].parent_to_child_fd[1],&tmpReq,sizeof(child_req_to_parent));
				waitpid(pidA[tmpReq.req.killed_req.tab_index],&status,0);
				pidA[tmpReq.req.killed_req.tab_index] = 0;
				printf("Tab Url Killed \n",NULL); //Don't need this
				return 3;
			}
		}
		
		else
		{
			perror("Reading Failed of Router Child Request \n");
			break;
		}
		
	}		


	return -1; //Implies that nothing was read
}

/*
 * Name:		new_tab_created_cb
 * Input arguments:	'button' - whose click generated this callback
 *			'data' - auxillary data passed along for handling
 *			this event.
 * Output arguments:    void
 * Function:		This is the callback function for the 'create_new_tab'
 *			event which is generated when the user clicks the '+'
 *			button in the controller-tab. The controller-tab
 *			redirects the request to the parent (/router) process
 *			which then creates a new child process for creating
 *			and managing this new tab.
 */ 
// We also refer to this as "create_new_tab_cb" in Appendix C.
void new_tab_created_cb(GtkButton *button, gpointer data)
{
	
	
	if(!data)
		return;
	comm_channel channel = ((browser_window*)data)->channel;

	// Append your code here.
	

	// Create new request.
	child_req_to_parent new_req;

	// Populate it with request type, CREATE_TAB, and tab index pulled from (browser_window*) data
	new_req.type = CREATE_TAB;
	((browser_window*)data)->tab_count += 1; //Since the browser window calling this function is the controller tab, only the controller tab window will be accessed here.
	new_req.req.new_tab_req.tab_index = ((browser_window*)data)->tab_count;
	
	//Send the request to the parent (/router) process through the proper FD.
	write(channel.child_to_parent_fd[1],&new_req,sizeof(child_req_to_parent));
	return;
}

/*
 * Name: 		create_proc_for_new_tab
 * Input arguments: 	tab_index: Tab index for which
 *			new child process is to be created.
 * Output arguments: 	0 -success
 *			-1-otherwise
 * Function:		Creates child process for managing
 *			new tab and establishes pipes for
 *			bi-directional communication.
 */

int create_proc_for_new_tab(comm_channel* channel, int tab_index, int actual_tab_cnt)
{

	pid_t pid;
	// Create bi-directional pipes (hence 2 pipes) for 
	// communication between the parent and child process.
	// Remember to error check.
	if((pipe(channel[tab_index].child_to_parent_fd) == -1) || (pipe(channel[tab_index].parent_to_child_fd) == -1))
	{
		perror("pipe error \n");
		exit(-1);
	}



	// Create child process for managing the new tab; remember to check for errors!
	// The first new tab is CONTROLLER, but the rest are URL-RENDERING type.
	pid = fork();
	if(pid == -1)
	{
		perror("Fork Error; Please Resart Program");
		exit(0); //Program error restart program
	}
	/* 
	if ...
	*/
	// If this is the child process,
	if(pid == 0)
	{
		
		//Child process should close unused pipes and launch
		// a window for either CONTROLLER or URL-RENDERING tabs.
		close(channel[tab_index].child_to_parent_fd[0]);
		close(channel[tab_index].parent_to_child_fd[1]);
		
		browser_window *b_window = NULL;

		// 'Tab 0' is the 'controller' tab. It is
		// this tab which receives browsing requests
		// from the user and redirects them to 
		// appropriate child tab via the parent.
		if(tab_index == 0) //This is the Controller Process
		{
			// Create the 'controller' tab
			create_browser((tab_type)CONTROLLER_TAB,tab_index,G_CALLBACK(new_tab_created_cb), G_CALLBACK(uri_entered_cb), &b_window,channel[tab_index]);
			// Display the 'controller' tab window.
			// Loop for events
			show_browser();
			exit(0);

		}
		else if((tab_index > 0) && (tab_index < 11))
		{
			int quit = 0;
			create_browser((tab_type)URL_RENDERING_TAB,tab_index,G_CALLBACK(new_tab_created_cb),G_CALLBACK(uri_entered_cb),&b_window,channel[tab_index]);
			// Create the 'ordinary' tabs.
			// These tabs render web-pages when
			// user enters url in 'controller' tabs.
			process_single_gtk_event();

			// Wait for the browsing requests.
			// User enters the url on the 'controller' tab
			// which redirects the request to appropriate
			// child tab via the parent-tab.
			while(quit == 0)
			{
				quit = wait_for_browsing_req(channel[tab_index].parent_to_child_fd, b_window); //NEED TO CODE STILL
				if(quit == -1)
				{
					perror("Please Try Again \n");
					quit = 0;
				}
			}
			exit(0);	
		}
	}
	else  // this is parent.
	{
		pidA[tab_index] = pid;
		// Parent Process: close proper FDs and start 
		// waiting for requests if the tab index is 0.		

		if(tab_index == 0) //Router Process as this would be the parent of the controller
		{
			close(channel[tab_index].child_to_parent_fd[1]);
			close(channel[tab_index].parent_to_child_fd[0]);

			int status = 0;
			int tabCount = 1;
			int totalTabs = 1;
			int done = 0;
			while(done == 0)
			{
				int nread = -1;
			
				while(nread == -1)
				{
					nread = wait_for_child_reqs(channel,totalTabs,tabCount);
				}
				if(nread == 1)
				{
					tabCount++;
					totalTabs++;
				}
				if(nread == 2)
				{
					//Url Entered	
				}
				if(nread == 3)
				{
					//Kill Tab 
					tabCount--;
				}
				if(nread == 4)
				{
					tabCount--;
					done = 1;
				}
				
				nread = -1; //To Reset and wait for new requests
			}
			waitpid(pidA[tab_index],&status,0);
			pidA[tab_index] = 0;
			kill_all(channel,totalTabs,tabCount);
		}
		

	}


	return 0;
}

/*  The Main function doesn't need to do much -
* create a comm_channel and create process for a
* new tab.  This first tab will become the main
* controller tab.  As always, you should modularize
* your code and separate functionality by making new
* functions responsible for such things as
* waiting for a browsing request, waiting for child requests,
* or create a process for a new tab.  We have provided
* suggestions and signatures but you are free to modify the 
* given code, as long as it still works.
*/

int main()
{
	comm_channel channel[11]; //One for the controller process, and 10 for the tabs
	pid_t pid;
	
	
	pid = fork();
	if(pid == 0) //Creates Controller Process
	{
		create_proc_for_new_tab(channel,0,0);
	}
	else
	{
		
	wait(NULL); //Used while testing code to make sure all children are done before parent exits
	}
	return 0;
}

